package rpc.frame.server.boot.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import rpc.frame.core.handler.RpcRequestHandler;
import rpc.frame.core.netty.codec.FrameDecoder;
import rpc.frame.core.netty.codec.FrameEncoder;
import rpc.frame.core.netty.codec.RpcRequestDecoder;
import rpc.frame.core.netty.codec.RpcResponseEncoder;
import rpc.frame.server.boot.FrameServer;
import rpc.frame.server.config.RpcServerConfiguration;

import javax.annotation.Resource;
import java.net.InetSocketAddress;

@Component
@Slf4j
public class NettyServer implements FrameServer {
    @Resource
    private RpcServerConfiguration rpcServerConfiguration;

    /**
     * netty
     * 1.创建一个客户端的serverChannel
     * 2.使用IO多路复用模型 监听注册 有注册创建channel 监听读写事件
     * 3.规定协议 使用 4字节 即一次加解码
     * 4.定义传输的 格式 进行二次加解码
     * 5.业务处理
     */
    @Override
    public void start() {
        //定义一个boss的线程池 设置线程数为1
        NioEventLoopGroup boss = new NioEventLoopGroup(1, new DefaultThreadFactory("boss"));
        //定义一个work的线程池 默认线程数 内核*2
        NioEventLoopGroup work = new NioEventLoopGroup(0, new DefaultThreadFactory("work"));
        //定义一个业务处理的线程池
        UnorderedThreadPoolEventExecutor business = new UnorderedThreadPoolEventExecutor(NettyRuntime.availableProcessors() * 2, new DefaultThreadFactory("business"));

        try {
            //创建监听 监听channel的时间
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss,work)
                    .channel(NioServerSocketChannel.class) //channel 类型
                    .option(ChannelOption.SO_BACKLOG,1024) //设置是否阻塞
                    .childOption(ChannelOption.TCP_NODELAY,true)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                                      @Override
                                      protected void initChannel(SocketChannel socketChannel) throws Exception {
                                          //添加 handler Netty 都是将数据放置在handler处理的
                                          ChannelPipeline pipeline = socketChannel.pipeline();
                                          //encode
                                          pipeline.addLast("firstEncode",new FrameEncoder());//加码 将字节数组安装协议加码
                                          pipeline.addLast("secondEncode",new RpcResponseEncoder());//将object 序列化=
                                          //decode、
                                          pipeline.addLast("firstDecode",new FrameDecoder());
                                          pipeline.addLast("secondDecode",new RpcRequestDecoder());
                                          //业务handler
                                          pipeline.addLast(business,"rpcRequestHandler",new RpcRequestHandler());

                                      }
                                  }

                    );

            ChannelFuture future = serverBootstrap.bind(new InetSocketAddress(rpcServerConfiguration.getRpcPort())).sync();

            //监听服务端channel 销毁
            future.channel().closeFuture().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    boss.shutdownGracefully();
                    work.shutdownGracefully();
                    business.shutdownGracefully();
                }
            });

            log.info("服务端连接成功");

        } catch (InterruptedException e) {
            log.error("start error msg={}",e);
            boss.shutdownGracefully();
            work.shutdownGracefully();
            business.shutdownGracefully();
            throw new RuntimeException(e);
        }


    }
}
